//
//  NSData+Tools.m
//  MiaoPai
//
//  Created by jiaxuzhou on 2017/6/10.
//  Copyright © 2017年 Jeakin. All rights reserved.
//
//


#import "NSData+Tools.h"
#import "MPBTools+EncryptDecrypt.h"
#import <zlib.h>


@implementation NSData (Tools)

/**
 注释

 @return 注释
 */
- (NSString *)mp_MD5Lower16
{
    return [MPBTools mp_EncryptByMD5Lower16Data:self];
}

- (NSString *)mp_MD5Upper16
{
    return [MPBTools mp_EncryptByMD5Upper16WithData:self];
}

+ (NSString *)mp_MD5Lower16:(NSData *)originalData
{
    return [MPBTools mp_EncryptByMD5Lower16Data:originalData];
}

+ (NSString *)mp_MD5Upper16:(NSData *)originalData
{
    return [MPBTools mp_EncryptByMD5Upper16WithData:originalData];
}

- (NSString *)mp_AES128HexEncryptPassword:(NSString *)aKey
{
    return [MPBTools mp_AES128HexEncryptData:self password:aKey];
}

- (NSString *)mp_AES128HexDecryptPassword:(NSString *)aKey
{
    return [MPBTools mp_AES128HexDecryptData:self password:aKey];
}

+ (NSString *)mp_AES128HexEncrypt:(NSData *)aData password:(NSString *)aKey
{
    return [MPBTools mp_AES128HexEncryptData:aData password:aKey];
}

+ (NSString *)mp_AES128HexDecrypt:(NSData *)aData password:(NSString *)aKey
{
    return [MPBTools mp_AES128HexDecryptData:aData password:aKey];
}

- (NSString *)mp_HEXEncrypt
{
    return [MPBTools mp_EncryptByHEXData:self];
}

- (NSData *)mp_HEXDecrypt
{
    return [MPBTools mp_DecryptByHEXData:self];
}

+ (NSString *)mp_HEXEncrypt:(NSData *)aData
{
    return [MPBTools mp_EncryptByHEXData:aData];
}

+ (NSData *)mp_HEXDecrypt:(NSData *)aData
{
    return [MPBTools mp_DecryptByHEXData:aData];
}

- (NSString *)mp_Base64Encrypt
{
    return [MPBTools mp_EncryptByBase64Data:self];
}

- (NSData *)mp_Base64Decrypt
{
    return [MPBTools mp_DecryptByBase64Data:self];

}

+ (NSString *)mp_Base64Encrypt:(NSData *)aData
{
    return [MPBTools mp_EncryptByBase64Data:aData];
}

+ (NSData *)mp_Base64Decrypt:(NSData *)aData
{
    return [MPBTools mp_DecryptByBase64Data:aData];
}


#pragma mark - ************************************ gzip压缩 ****************************************

- (NSData *)mp_gzippedDataWithCompressionLevel:(float)level
{
    if ([self length])
    {
        z_stream stream;
        stream.zalloc = Z_NULL;
        stream.zfree = Z_NULL;
        stream.opaque = Z_NULL;
        stream.avail_in = (uint)[self length];
        stream.next_in = (Bytef *)[self bytes];
        stream.total_out = 0;
        stream.avail_out = 0;
        
        int compression = (level < 0.0f)? Z_DEFAULT_COMPRESSION: (int)(roundf(level * 9));
        if (deflateInit2(&stream, compression, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY) == Z_OK)
        {
            NSMutableData *data = [NSMutableData dataWithLength:ChunkSize];
            while (stream.avail_out == 0)
            {
                if (stream.total_out >= [data length])
                {
                    data.length += ChunkSize;
                }
                stream.next_out = (uint8_t *)[data mutableBytes] + stream.total_out;
                stream.avail_out = (uInt)([data length] - stream.total_out);
                deflate(&stream, Z_FINISH);
            }
            deflateEnd(&stream);
            data.length = stream.total_out;
            
            return data;
        }
    }
    
    return nil;
}

- (NSData *)mp_gzippedData
{
    return [self mp_gzippedDataWithCompressionLevel:-1.0f];
}

- (NSData *)mp_gunzippedData
{
    if ([self length])
    {
        z_stream stream;
        stream.zalloc = Z_NULL;
        stream.zfree = Z_NULL;
        stream.avail_in = (uint)[self length];
        stream.next_in = (Bytef *)[self bytes];
        stream.total_out = 0;
        stream.avail_out = 0;
        
        NSMutableData *data = [NSMutableData dataWithLength:(NSUInteger)([self length] * 1.5)];
        if (inflateInit2(&stream, 47) == Z_OK)
        {
            int status = Z_OK;
            while (status == Z_OK)
            {
                if (stream.total_out >= [data length])
                {
                    data.length += [self length] / 2;
                }
                stream.next_out = (uint8_t *)[data mutableBytes] + stream.total_out;
                stream.avail_out = (uInt)([data length] - stream.total_out);
                status = inflate (&stream, Z_SYNC_FLUSH);
            }
            if (inflateEnd(&stream) == Z_OK)
            {
                if (status == Z_STREAM_END)
                {
                    data.length = stream.total_out;
                    return data;
                }
            }
        }
    }
    
    return nil;
}


@end
